package telin;

import gate.*;
import gate.creole.*;
import gate.creole.ontology.*;
import gate.util.GateRuntimeException;
import gate.util.InvalidOffsetException;
import gate.util.LuckyException;
import gate.util.Out;

import java.util.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import ru.edu.niimm.mapping.linguistic.NLPServers;
import LemmatizerWrapper.Wordform;
import LemmatizerWrapper.LemClient;
import LemmatizerWrapper.Paradigm;
import ru.edu.niimm.mapping.linguistic.Template;
import ru.edu.niimm.mapping.linguistic.ThesTemplates;

/**
 * GATE Processing Resource
 *
 * @author Telematica Instituut, Christian Wartena
 */
public class Apolda extends AbstractLanguageAnalyser {

    public static final String LOOKUP_INSTANCE_FEATURE_NAME = "identifier";
    public static final String CONCEPT_FEATURE_NAME = "Mention";

    private static final String EXC_NOONT = "Please specify an ontology!";
    private static final String EXC_ABRUPT = "The execution of appolda has been abruptly interrupted!";
    private static final String EXC_NODOC = "No document to process!";
    private static final String EXC_NOTOKENS = "You need to run a Tokenizer first!";
    private static final String DOCPROP_NROFTOK = "Number of tokens";
    private static final String DOCPROP_NROFCONCEPTS = "Number of recognized concepts";
    private static final String STATUS_STARTDOC = "Doing ontology lookup in";
    private static final String STATUS_ENDDOC = "Ontology lookup complete!";
    private static final String STATUS_STARTREADONT = "Reading ontology";
    private static final String STATUS_ENDREADONT = "term representations read";

    private String inputASname, outputASname;

    private Locale language;

    private String lemmaFeature = null;

    private String sURL;

    private String prefRepresentation = null;

    private String altRepresentation = null;

    private Ontology ontology;

    /**
     * The initial state of the FSM that backs this gazetteer
     */
    protected FSMState initialState;

    /**
     * A set containing all the states of the FSM backing the gazetteer
     */
    protected Set fsmStates;
    //    private static String serverName = "217.66.17.37";

    //private static String serverName = "192.168.5.220";

//    private static String serverName = "localhost";

    private LemClient client;

    public Apolda() {
        System.out.println("Apolda with Russian morphology 1.3");
        client = new LemClient ();
        //int port = 8000;
//        String host = LemClient.getHostName();

        client.init(NLPServers.serverName, 8000);
//        client.init("302-1", 8000);

        String msg_load = client.LemLoadDict("RUSSIAN"); //"RUSSIAN");
//        String msg_load = client.LemLoadDict("ENGLISH"); //"RUSSIAN");
        if(!msg_load.equals("OK"))
        {
            System.out.println("Error in loading RUSSIAN dictonary (LemServer) : " + msg_load);
        }
        client.LemSetPrintingAllForms(true);

       /* clientEng = new LemClient ();
        clientEng.init(serverName, 8001);

        msg_load = clientEng.LemLoadDict("ENGLISH"); //"RUSSIAN");
                if(!msg_load.equals("OK"))
                {
                    System.out.println("Error in loading ENGLISH dictonary (LemServer) : " + msg_load);
                }
                clientEng.LemSetPrintingAllForms(true);*/

    }

    public String getInputASName() {
        return inputASname;
    }

    public void setInputASName(String inputASname) {
        this.inputASname = inputASname;
    }

    public String getOutputASName() {
        return outputASname;
    }

    public void setOutputASName(String outputASname) {
        this.outputASname = outputASname;
    }

    public String getLemmaFeature() {
        return lemmaFeature;
    }

    public void setLemmaFeature(String lemmaFeature) {
        this.lemmaFeature = lemmaFeature;
    }

    public Resource init() throws ResourceInstantiationException {


        if (ontology == null) {
            throw new ResourceInstantiationException(EXC_NOONT);
        }

        fsmStates = new HashSet();
        initialState = new FSMState();
        fsmStates.add(initialState);
        readOntology();

        return this;
    }

    private int addAnnotation(AnnotationSet annotationSet, Set lookupSet, Region matchedRegion) {
        Term currentTerm;
        FeatureMap fm;
        int nrOfAnnotations = 0;
        Iterator lookupIter = lookupSet.iterator();

        while (lookupIter.hasNext())
        {
            currentTerm = (Term) lookupIter.next();
            fm = Factory.newFeatureMap();
            fm.put(LOOKUP_CLASS_FEATURE_NAME, currentTerm.oClass);
            fm.put(LOOKUP_ONTOLOGY_FEATURE_NAME, currentTerm.ontology);

            if (!currentTerm.oIdentifier.equals(""))
            {
                fm.put(LOOKUP_INSTANCE_FEATURE_NAME, currentTerm.oIdentifier);
            }

            try
            {
                annotationSet.add(new Long(matchedRegion.getBegin()), new Long(
                        matchedRegion.getEnd() + 1), CONCEPT_FEATURE_NAME, fm);
                nrOfAnnotations++;
            }
            catch (InvalidOffsetException ioe)
            {
                throw new LuckyException(ioe.toString());
            }
        }// while(lookupIter.hasNext())

        return nrOfAnnotations;
    }

    private int findConcepts(Content theContent, AnnotationSet outputAnnSet)
            throws ExecutionException
    {
        int nrOfAnnotations = 0;
        int iterations = 0;
        char currentChar;
        FSMState currentState = initialState;
        FSMState nextState;
        FSMState lastMatchingState = null;
        Region lastMatchingRegion = null;
        Set termSet;

        while (theContent.more())
        {
            currentChar = theContent.getNextChar(currentState);
            currentChar = Character.toUpperCase(currentChar);
            nextState = currentState.next(currentChar);
            if (nextState == null)
            {
                // the matching stopped
                // Try backtracking in order to find a longer match
                currentState = theContent.redo();
                if(currentState == null)
                {
                    // reset the FSM
                    currentState = initialState;
                    theContent.forward(currentState);

                    // if we had a successful match then act on it;
                    if (lastMatchingState != null && lastMatchingRegion != null)
                    {
                        termSet = checkMatchingTerms(lastMatchingRegion, lastMatchingState.getTermSet());
                        if(termSet != null)
                        {
                            nrOfAnnotations += addAnnotation(outputAnnSet, termSet,	lastMatchingRegion);
                            lastMatchingState = null;
                        }
                    }
                }
            }
            else
            {
                // go on with the matching
                currentState = nextState;
                // if we have a successful state then store it
                if (currentState.isFinal() && theContent.atEndOfWord())
                {
                    Region r = theContent.getCurrentRegion();
                    if(lastMatchingRegion == null || !lastMatchingRegion.contains(r))
                    {
                        lastMatchingState = currentState;
                        lastMatchingRegion = r;
                    }
                }
            }

            if((iterations++)%256 == 0 && isInterrupted())
            {
                throw new ExecutionInterruptedException(EXC_ABRUPT);
            }

        } //while (theContent.more())

        if (lastMatchingState != null)
        {
            termSet = checkMatchingTerms(lastMatchingRegion, lastMatchingState.getTermSet());
            if(termSet != null)
                nrOfAnnotations += addAnnotation(outputAnnSet, termSet, lastMatchingRegion);
        }

        return nrOfAnnotations;
    }

    private Set checkMatchingTerms(Region matchingRegion, Set termSet)
            throws ExecutionException
    {
        Set newTermSet = new HashSet();
        Iterator termSetIt = termSet.iterator();
        Term term;
        Long begin;
        Long end;
        String literalText = null;
        List representations;

        while(termSetIt.hasNext())
        {
            term = (Term) termSetIt.next();
            if(term.type == Term.STANDARD)
            {
                newTermSet.add(term);
            }
            else
            {
                if(literalText == null)
                {
                    try
                    {
                        begin = new Long(matchingRegion.getBegin());
                        end = new Long(matchingRegion.getEnd() + 1);
                        literalText = document.getContent().getContent(begin,end).toString();
                    }
                    catch(InvalidOffsetException e)
                    {
                        throw new ExecutionException(e);
                    }
                }

                representations = term.getRepresentations();
                if((representations != null && representations.contains(literalText.toUpperCase())))
                {
                    newTermSet.add(term);
                }
//                String repr = "";
//                for(Iterator itr = representations.iterator(); itr.hasNext();repr = (String) itr.next())
//                {
//                    if(repr.contains(literalText) || literalText.contains(repr))
//                    {
//                       newTermSet.add(term);
//                    }
//                }

            }
        }
        return newTermSet;
    }

    public void execute() throws ExecutionException
    {
        int nrOfAnnotations = 0;
//        System.out.println("my Rus Apolda");
        try
        {
            // check the parameters
            if (document == null)
            {
                throw new GateRuntimeException(EXC_NODOC);
            }

            AnnotationSet inputAnnSet = inputASname == null
                    || inputASname.length() == 0 ? document.getAnnotations()
                    : document.getAnnotations(inputASname);

            AnnotationSet outputAnnSet = outputASname == null
                    || outputASname.length() == 0 ? document.getAnnotations()
                    : document.getAnnotations(outputASname);

            fireStatusChanged(STATUS_STARTDOC + " " + document.getName() + "...");

            try
            {
                document.getFeatures().put(
                        DOCPROP_NROFTOK,
                        Integer.toString(inputAnnSet.get(RusApoldaConstants.TOKEN_ANNOTATION_TYPE).size()));
            }
            catch (NullPointerException e)
            {
                throw new ExecutionException(EXC_NOTOKENS);
            }

            Content theContent = new Content(inputAnnSet, lemmaFeature);

            theContent.forward(initialState);

            nrOfAnnotations = findConcepts(theContent, outputAnnSet);

            document.getFeatures().put(DOCPROP_NROFCONCEPTS, new Integer(nrOfAnnotations).toString());

            fireProcessFinished();
            fireStatusChanged(STATUS_ENDDOC);
        }

        catch (NullPointerException ex)
        {
            Out.prln("");
        }
        catch (Exception e)
        {
            throw new ExecutionException(e);
        }
//        System.out.println("my Rus Apolda finished.");
    }

    private void addRepresentationToList(List representationsLit,
                                         List representationsStand, String representation) {
        int len;

        len = representation.length();
        if (len > 2 && representation.charAt(0) == '"'
                && representation.charAt(len - 1) == '"')
        {
            representation = representation.substring(1, len - 1);
            representationsLit.add(representation.toUpperCase());
            System.out.println("LitRepr: " + representation.toUpperCase());
        }
        else
        {
            representationsStand.add(representation.toUpperCase());
            System.out.println("StandRepr: " + representation.toUpperCase());
        }
    }


    private ArrayList<String> extractTemplateDates(Template template, String words[], List representationsLit,
                                                   List representationsStand, OResource concept)
    {
        for(int i = 0; i < words.length; i++)
        {
            String word = words[i];
            if(template.checkDateTemplateOn(word))
            {
                addRepresentationToList(representationsLit, representationsStand, word);
            }
        }
        return null;
    }

    private ArrayList<String> extractTemplateCentury(Template template, String words[], List representationsLit,
                                                   List representationsStand, OResource concept)
    {
        for(int i = 0; i < words.length; i++)
        {
            String word = words[i];
            if(template.checkCenturyTemplateOn(word))
            {
                addRepresentationToList(representationsLit, representationsStand, word);
            }
        }
        return null;
    }

    /**
 * The interface for objects which have an adjustable numeric value
 * contained within a bounded range of values.
 * @param template шаблон
 * @param words исходный текстовый комментарий
 * @param representationsLit список литеральных представлений
 * @param representationsStand список стандартизированных представлений
 */
    private ArrayList<String> extractTemplateTerms(Template template, String words[],
                                                   List representationsLit,
                                                   List representationsStand)
    {

        Map<String,Wordform> wordforms = LemClient.createEmptyWordformMap();
        Map<Integer,Paradigm> paradigms= LemClient.createEmptyParadigmMap();

        if(words.length > 0 && ! words[0].equalsIgnoreCase(""))
        {
            client.createWordformAndParadigm(words, wordforms, paradigms);
            if(words.length > 3)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(words.length);
                String lemma = "";
                String text = "";
                for(int i = 0; i < words.length; i++)
                {
                    String word = words[i];
                    if(wordforms.containsKey(word))
                    {
                        Wordform w = wordforms.get(word);
                        if(w != null)
                        {
                            wforms.add(w);
                            text += w.word + " ";
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                // надо учитывать варианты парадигм: многозначные слова !!!
                                // а здесь всегда берется первая из списка
                                lemma += w.paradigms[0].lemma + " ";
                            }
                        }
                    }
                }
                if(! (lemma.trim()).equalsIgnoreCase("") )
                {
                addRepresentationToList(representationsLit,
                        representationsStand, lemma.trim());
                }
                addRepresentationToList(representationsLit,
                        representationsStand, text.trim());
            }
            // термин 3-х и более словный
            if(words.length == 3)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(3);
                String lemma = null;
                // окно по 3 слова
                for(int i = 2; i < words.length; i++)
                {
                    // первое слово в трехсловном термине
                    String word = words[i - 2];
                    if(wordforms.containsKey(word))
                    {
                        Wordform w = wordforms.get(word);
                        if(w != null)
                        {
                            wforms.add(w);
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                // надо учитывать варианты парадигм: многозначные слова !!!
                                // а здесь всегда берется первая из списка
                                lemma = w.paradigms[0].lemma;
                            }
                        }
                    }
                    // второе слово в трехсловном термине
                    String word2 = words[i - 1];
                    if(wordforms.containsKey(word2))
                    {
                        Wordform w = wordforms.get(word2);
                        if(w != null)
                        {
                            wforms.add(w);
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                if(lemma != null)
                                {
                                    lemma += " " + w.paradigms[0].lemma;
                                }
                            }
                        }
                    }
                    // третье слово в трехсловном термине
                    String word3 = words[i];
                    if(wordforms.containsKey(word3))
                    {
                        Wordform w = wordforms.get(word3);
                        if(w != null)
                        {
                            wforms.add(w);
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                if(lemma != null)
                                {
                                    lemma += " " + w.paradigms[0].lemma;
                                }
                            }
                        }
                    }
                    if(lemma != null)
                {
                    addRepresentationToList(representationsLit,
                            representationsStand, lemma.trim());
                }
                    addRepresentationToList(representationsLit,
                            representationsStand, word + " " + word2 + " " + word3);

                    /*
                    if(template.checkTemplateOn(wforms))
                    {
                        if(lemma != null && lemma.lastIndexOf(" ") != lemma.indexOf(" "))
                        {

                            addRepresentationToList(representationsLit,
                                    representationsStand, lemma);
                            System.out.println("3W " + lemma);
                            //Literal syntaxTemplate = new Literal(lemma, OConstants.RUSSIAN);
                            //@todo collect syntax templates
                            //concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);
                        }
                        else
                        {
                            addRepresentationToList(representationsLit,
                                    representationsStand, word + " " + word2 + " " + word3);
                            System.out.println("3W_ " + word + " " + word2 + " " + word3);
                            //Literal syntaxTemplate = new Literal(word + " " + word2 + " " + word3, OConstants.RUSSIAN);
                            //@todo collect syntax templates
                            //concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);
                        }
                    }*/
                }
            }

            // для 2-х словного термина
            if(words.length == 2)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(2);
                String lemma = null;
                // первое слово
                String word = words[0];
                if(wordforms.containsKey(word))
                {
                    Wordform w = wordforms.get(word);
                    if(w != null)
                    {
                        wforms.add(w);
                        if(w.paradigms != null)
                        {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                            if(w.paradigms.length > 1)
                            {
                                System.out.println("lexical ambiguity! ("+w.paradigms.length+")" + w.paradigms[1].lemma);

                                for (Paradigm para : w.paradigms)
                                {
                                    if(para.pos.equalsIgnoreCase("С"))
                                    {
                                        System.out.println("Solved with " + para.lemma);
                                        lemma = para.lemma + " ";
                                        break;
                                    }
                                    else if(para.pos.equalsIgnoreCase("П"))
                                    {
                                        System.out.println("Solved with " + para.lemma);
                                        lemma = para.lemma + " ";
                                        break;
                                    }

                                }
                            }
                            else
                            {
                                lemma = w.paradigms[0].lemma + " ";
                            }
                        }
                    }
                }

                // второе слово
                String word2 = words[1];
                if(wordforms.containsKey(word2))
                {
                    Wordform w = wordforms.get(word2);
                    if(w != null)
                    {
                        wforms.add(w);
                        if(w.paradigms != null)
                        {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                            if(lemma != null)
                            {
                                if(w.paradigms.length > 1)
                                {
                                    System.out.println("lexical ambiguity! ("+w.paradigms.length+")" + w.paradigms[1].lemma);

                                    for (Paradigm para : w.paradigms)
                                    {
                                        if(para.pos.equalsIgnoreCase("С"))
                                        {
                                            System.out.println("Solved with " + para.lemma);
                                            lemma += para.lemma;
                                            break;
                                        }
                                        else if(para.pos.equalsIgnoreCase("П"))
                                        {
                                            System.out.println("Solved with " + para.lemma);
                                            lemma += para.lemma;
                                            break;
                                        }

                                    }
                                }
                                else
                                {
                                    lemma +=  w.paradigms[0].lemma;
                                }
                            }
                        }
                    }
                }

                if(lemma != null)
                {
                addRepresentationToList(representationsLit,
                        representationsStand, lemma.trim());
                }
                addRepresentationToList(representationsLit,
                        representationsStand, word + " " + word2);


                // сопоставление с грамматическим шаблоном
                /* if(template.checkTemplateOn(wforms))
                {
                    if(lemma != null)
                    {
                        // в combinedLemma слова переставлены местами
                        // в lemma прямой порядок слов

                        String combinedLemma = lemma.substring(lemma.indexOf(' ')).trim() + " " +
                                lemma.substring(0, lemma.indexOf(' ') + 1).trim();

                        addRepresentationToList(representationsLit,
                                representationsStand, lemma);
                        System.out.println("2W " + lemma);
//                        Literal syntaxTemplate = new Literal(lemma, OConstants.RUSSIAN);
                        //@todo collect syntax templates
//                        concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);

                        addRepresentationToList(representationsLit,
                                representationsStand, combinedLemma);

//   syntaxTemplate = new Literal(combinedLemma, OConstants.RUSSIAN);
                        //@todo collect syntax templates
//                        concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);
                    }
                    else
                    {
                        addRepresentationToList(representationsLit,
                                representationsStand, word + " " + word2);
                        System.out.println("2W_ " + word + " " + word2);
//                        Literal syntaxTemplate = new Literal(word + " " + word2, OConstants.RUSSIAN);
                        //@todo collect syntax templates
//                        concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);

                        addRepresentationToList(representationsLit,
                                representationsStand, word2 + " " + word);
//                        syntaxTemplate = new Literal(word2 + " " + word, OConstants.RUSSIAN);
                        //@todo collect syntax templates
//                        concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);
                    }
                }*/
            }
            // однословный термин
            if(words.length == 1)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(1);
                // единственное слово однословного термина
                String word = words[0];
                String lemma = null;
                if(wordforms.containsKey(word))
                {
                    Wordform w = wordforms.get(word);
                    wforms.add(w);
                    if(w.paradigms != null)
                    {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                        if(w.paradigms.length > 1)
                        {
                            System.out.println("lexical ambiguity! ("+w.paradigms.length+")" + w.paradigms[1].lemma);

                            for (Paradigm para : w.paradigms)
                            {
                                if(para.pos.equalsIgnoreCase("С"))
                                {
                                    System.out.println("Solved with " + para.lemma);
                                    lemma = para.lemma;
                                    break;
                                }
                                else if(para.pos.equalsIgnoreCase("П"))
                                {
                                    System.out.println("Solved with " + para.lemma);
                                    lemma = para.lemma;
                                    break;
                                }

                            }
                        }
                        else
                        {
                            lemma = w.paradigms[0].lemma;
                        }
                    }
                }

                if(lemma != null)
                {
                addRepresentationToList(representationsLit,
                        representationsStand, lemma);
                }
                addRepresentationToList(representationsLit,
                        representationsStand, word);

                //проверка на соответствие шаблону
                /* if(template.checkTemplateOn(wforms))
                {
                    if(lemma != null)
                    {
                        addRepresentationToList(representationsLit,
                                representationsStand, lemma);
                        System.out.println("1W " + lemma);
                       // Literal syntaxTemplate = new Literal(lemma.trim(), OConstants.RUSSIAN);
                        //@todo collect syntax templates
                        //concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);
                    }
                    else
                    {
                        addRepresentationToList(representationsLit,
                                representationsStand, word);
                        System.out.println("1W_ " + word);
//                        Literal syntaxTemplate = new Literal(word.trim(), OConstants.RUSSIAN);
                        //@todo collect syntax templates
//                        concept.addAnnotationPropertyValue(altRepresentationAP, syntaxTemplate);
                    }
                }*/
            }
        }
        return null;
    }

    private ArrayList<String> extractEnglishTemplateTerms(String words[],
                                                   List representationsLit,
                                                   List representationsStand)
    {
        Map<String,Wordform> wordforms = LemClient.createEmptyWordformMap();
        Map<Integer,Paradigm> paradigms= LemClient.createEmptyParadigmMap();

        if(words.length > 0 && ! words[0].equalsIgnoreCase(""))
        {

            client.createWordformAndParadigm(words, wordforms, paradigms);
            if(words.length > 3)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(words.length);
                String lemma = "";
                String text = "";
                for(int i = 0; i < words.length; i++)
                {
                    String word = words[i];
                    if(wordforms.containsKey(word))
                    {
                        Wordform w = wordforms.get(word);
                        if(w != null)
                        {
                            wforms.add(w);
                            text += w.word + " ";
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                // надо учитывать варианты парадигм: многозначные слова !!!
                                // а здесь всегда берется первая из списка
                                lemma += w.paradigms[0].lemma + " ";
                            }
                        }
                    }
                }
                if(! (lemma.trim()).equalsIgnoreCase("") )
                {
                addRepresentationToList(representationsLit,
                        representationsStand, lemma.trim());
                }
                addRepresentationToList(representationsLit,
                        representationsStand, text.trim());
            }
            // термин 3-х и более словный
            if(words.length == 3)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(3);
                String lemma = null;
                // окно по 3 слова
                for(int i = 2; i < words.length; i++)
                {
                    // первое слово в трехсловном термине
                    String word = words[i - 2];
                    if(wordforms.containsKey(word))
                    {
                        Wordform w = wordforms.get(word);
                        if(w != null)
                        {
                            wforms.add(w);
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                // надо учитывать варианты парадигм: многозначные слова !!!
                                // а здесь всегда берется первая из списка
                                lemma = w.paradigms[0].lemma;
                            }
                        }
                    }
                    // второе слово в трехсловном термине
                    String word2 = words[i - 1];
                    if(wordforms.containsKey(word2))
                    {
                        Wordform w = wordforms.get(word2);
                        if(w != null)
                        {
                            wforms.add(w);
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                if(lemma != null)
                                {
                                    lemma += " " + w.paradigms[0].lemma;
                                }
                            }
                        }
                    }
                    // третье слово в трехсловном термине
                    String word3 = words[i];
                    if(wordforms.containsKey(word3))
                    {
                        Wordform w = wordforms.get(word3);
                        if(w != null)
                        {
                            wforms.add(w);
                            if(w.paradigms != null)
                            {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                                if(lemma != null)
                                {
                                    lemma += " " + w.paradigms[0].lemma;
                                }
                            }
                        }
                    }
                    if(lemma != null)
                {
                    addRepresentationToList(representationsLit,
                            representationsStand, lemma.trim());
                }
                    addRepresentationToList(representationsLit,
                            representationsStand, word + " " + word2 + " " + word3);


                }
            }
//
            // для 2-х словного термина
            if(words.length == 2)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(2);
                String lemma = null;
                // первое слово
                String word = words[0];
                if(wordforms.containsKey(word))
                {
                    Wordform w = wordforms.get(word);
                    if(w != null)
                    {
                        wforms.add(w);
                        if(w.paradigms != null)
                        {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                            if(w.paradigms.length > 1)
                            {
                                System.out.println("lexical ambiguity! ("+w.paradigms.length+")" + w.paradigms[1].lemma);

                                for (Paradigm para : w.paradigms)
                                {
                                    if(para.pos.equalsIgnoreCase("NOUN"))
                                    {
                                        System.out.println("Solved with " + para.lemma);
                                        lemma = para.lemma + " ";
                                        break;
                                    }
                                    else if(para.pos.equalsIgnoreCase("ADJECTIVE"))
                                    {
                                        System.out.println("Solved with " + para.lemma);
                                        lemma = para.lemma + " ";
                                        break;
                                    }

                                }
                            }
                            else
                            {
                                lemma = w.paradigms[0].lemma + " ";
                            }
                        }
                    }
                }

                // второе слово
                String word2 = words[1];
                if(wordforms.containsKey(word2))
                {
                    Wordform w = wordforms.get(word2);
                    if(w != null)
                    {
                        wforms.add(w);
                        if(w.paradigms != null)
                        {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                            if(lemma != null)
                            {
                                if(w.paradigms.length > 1)
                                {
                                    System.out.println("lexical ambiguity! ("+w.paradigms.length+")" + w.paradigms[1].lemma);

                                    for (Paradigm para : w.paradigms)
                                    {
                                        if(para.pos.equalsIgnoreCase("NOUN"))
                                        {
                                            System.out.println("Solved with " + para.lemma);
                                            lemma += para.lemma;
                                            break;
                                        }
                                        else if(para.pos.equalsIgnoreCase("ADJECTIVE"))
                                        {
                                            System.out.println("Solved with " + para.lemma);
                                            lemma += para.lemma;
                                            break;
                                        }

                                    }
                                }
                                else
                                {
                                    lemma +=  w.paradigms[0].lemma;
                                }
                            }
                        }
                    }
                }

                if(lemma != null)
                {
                addRepresentationToList(representationsLit,
                        representationsStand, lemma.trim());
                }
                addRepresentationToList(representationsLit,
                        representationsStand, word + " " + word2);



            }
//            // однословный термин
            if(words.length == 1)
            {
                List<Wordform> wforms = new ArrayList<Wordform>(1);
                // единственное слово однословного термина
                String word = words[0];
                String lemma = null;
                if(wordforms.containsKey(word))
                {
                    Wordform w = wordforms.get(word);
                    wforms.add(w);
                    if(w.paradigms != null)
                    {
//                                        lemma = w.paradigms[0].lemma + "@" + w.paradigms[0].pos + "$" + w.paradigms[0].joinCommonAnCodes(",");
                        if(w.paradigms.length > 1)
                        {
                            System.out.println("lexical ambiguity! ("+w.paradigms.length+")" + w.paradigms[1].lemma);

                            for (Paradigm para : w.paradigms)
                            {
                                if(para.pos.equalsIgnoreCase("NOUN"))
                                {
                                    System.out.println("Solved with " + para.lemma);
                                    lemma = para.lemma;
                                    break;
                                }
                                else if(para.pos.equalsIgnoreCase("ADJECTIVE"))
                                {
                                    System.out.println("Solved with " + para.lemma);
                                    lemma = para.lemma;
                                    break;
                                }

                            }
                        }
                        else
                        {
                            lemma = w.paradigms[0].lemma;
                        }
                    }
                }

                if(lemma != null)
                {
                addRepresentationToList(representationsLit,
                        representationsStand, lemma);
                }
                addRepresentationToList(representationsLit,
                        representationsStand, word);
            }
        }
        return null;

    }

    private void getRepresentations(OResource concept,
                                    List representationsLit, List representationsStand)
    {
        if (prefRepresentation == null && altRepresentation == null)
        {
            String strRepresentation = concept.getName();
            if (strRepresentation != null)
            {
                strRepresentation = strRepresentation.trim();
                addRepresentationToList(representationsLit,
                        representationsStand, strRepresentation);
            }
        }

        if (prefRepresentation != null)
        {
            AnnotationProperty prefRepresentationAP = (AnnotationProperty) ontology.getOResourceByName(prefRepresentation);
            List propValL = concept.getAnnotationPropertyValues(prefRepresentationAP);

            if (propValL != null) {
                for (Object aPropValL : propValL)
                {
                    Literal representation = (Literal) aPropValL;
                    Locale repLang = representation.getLanguage();

                    if (repLang != null && ! repLang.getLanguage().equalsIgnoreCase("") &&
                            (repLang.getLanguage().equalsIgnoreCase(OConstants.RUSSIAN.getLanguage()) ||
                            repLang.getLanguage().equalsIgnoreCase(OConstants.ENGLISH.getLanguage())) )
                    {
                        String strRepresentation = representation.getValue();
                        {
                        String semanticMarker = null;
                        if (strRepresentation.matches(".*\\(.*\\).*"))
                        {
                            semanticMarker = strRepresentation.substring(strRepresentation.indexOf('('),
                                    strRepresentation.indexOf(')') + 1);
                        }

                        if (semanticMarker != null)
                        {
                            strRepresentation = strRepresentation.substring(0, strRepresentation.indexOf('('));
                        }

                        strRepresentation = strRepresentation.
                                replaceAll("[.,/,,\",;,:,, ,-,',`,\\\\]", "_");

                        strRepresentation = strRepresentation.
                                replaceAll("[_]+", " ").trim();

                        Out.println("LABEL: " + strRepresentation);

                        String [] words = null;
                        if (!strRepresentation.startsWith("LEMMA"))
                        {
//                             addRepresentationToList(representationsLit,
//                                    representationsStand, strRepresentation);
//                            words = strRepresentation.split(" ");
//                            extractTemplateTerms(ThesTemplates.t2, words, representationsLit, representationsStand);
//                            extractTemplateTerms(ThesTemplates.t1, words, representationsLit, representationsStand);
//                            extractTemplateTerms(ThesTemplates.t3, words, representationsLit, representationsStand);
//                            extractTemplateDates(ThesTemplates.dyyyy, words, representationsLit, representationsStand, concept);
//                            extractTemplateCentury(ThesTemplates.century, words, representationsLit, representationsStand, concept);
//                            extractEnglishTemplateTerms(words, representationsLit, representationsStand);
//                            addRepresentationToList(representationsLit,
//                                    representationsStand, strRepresentation.trim());
                        }
                        else
                        {
//                            words = strRepresentation.substring(6).split(" ");
                            addRepresentationToList(representationsLit,
                                    representationsStand, strRepresentation.substring(6).trim());

                        }

//                        extractTemplateTerms(ThesTemplates.t2, words, representationsLit, representationsStand);
//                        extractTemplateTerms(ThesTemplates.t1, words, representationsLit, representationsStand);
//                        extractTemplateTerms(ThesTemplates.t3, words, representationsLit, representationsStand);
//                        extractTemplateTerms(ThesTemplates.t5, words, representationsLit, representationsStand);
//                        extractTemplateTerms(ThesTemplates.t3SPS, words, representationsLit, representationsStand);
//                        extractTemplateDates(ThesTemplates.dyyyy, words, representationsLit, representationsStand, concept);
                    }
                    }
                }
            }
        }
    }

    private void readOntology()
    {
        fireStatusChanged(STATUS_STARTREADONT);

        sURL = ontology.getURL().toString();
        int nrOfStrings = 0;

        Set concepts = ontology.getOClasses(false);
        Iterator conceptIt = concepts.iterator();
        OClass concept;

        while (conceptIt.hasNext()) {
            concept = (OClass) conceptIt.next();
            Term termLit = new Term(concept.getName(), concept.getName(), sURL,Term.LITERAL);
            Term termGlob = new Term(concept.getName(), concept.getName(), sURL,Term.STANDARD);
            List representationsLit = new Vector();
            List representationsStandard = new Vector();
            getRepresentations(concept, representationsLit, representationsStandard);
            termLit.setRepresentations(representationsLit);
            nrOfStrings += addTermRepresentations(termLit, representationsLit);
            nrOfStrings += addTermRepresentations(termGlob, representationsStandard);
            nrOfStrings += readInstances(concept);
        }
        Out.println(new Integer(nrOfStrings).toString() + " " + STATUS_ENDREADONT);
        /*
        вывод индексирующей онтологии в файл
        File f = new File("testOntoPOS.owl");
        try {
            FileWriter fw = new FileWriter(f);
            fw.write(ontology.getOntologyData(OConstants.ONTOLOGY_FORMAT_RDFXML));
            fw.flush();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }*/
    }

    private int readInstances(OClass concept){
        Out.println("CLASS: "+concept.getName());
        Set instances = ontology.getOInstances(concept, OConstants.DIRECT_CLOSURE);
        Iterator instIt = instances.iterator();
        OInstance inst;
        int rc = 0;

        while (instIt.hasNext()) {
            inst = (OInstance) instIt.next();
            Out.println("INSTANCE: " + inst.getName());
            Term termLit = new Term(concept.getName(), inst.getName(), sURL, Term.LITERAL);
            Term termGlob = new Term(concept.getName(), inst.getName(), sURL, Term.STANDARD);
            List representationsLit = new Vector();
            List representationsStandard = new Vector();
            getRepresentations(inst, representationsLit, representationsStandard);
            termLit.setRepresentations(representationsLit);
            rc += addTermRepresentations(termLit, representationsLit);
            rc += addTermRepresentations(termGlob, representationsStandard);
        }
        return rc;
    }

    private int addTermRepresentations(Term term, List representations) {
        int rc = 0;

        if(representations != null) {
            Iterator representation = representations.iterator();
            while (representation.hasNext())
            {
                addTermRepresentation((String) representation.next(), term);
                rc++;
            }
        }

        return rc;
    }

    private void addTermRepresentation(String representation, Term term) {
        char currentChar;
        FSMState currentState = initialState;
        FSMState nextState;
        boolean isSpace;

        for (int i = 0; i < representation.length(); i++)
        {
            currentChar = representation.charAt(i);
            isSpace = Character.isWhitespace(currentChar);
            // пропуск любого числа пробельных символов
            if (isSpace)
            {
                if(i > 0 && Character.isWhitespace(representation.charAt(i-1)))
                    continue;
                else
                    currentChar = ' ';
            }

            else
                currentChar = Character.toUpperCase(currentChar);

            // смотрим следующее состояния машины на основе текущего символа
            // строим функцию переходов transitionFunction как CharMap (см. FSMState)
            nextState = currentState.next(currentChar);

            // если такого состояния еще нет в функции
            if (nextState == null)
            {
                // то создаем его
                nextState = new FSMState();
                // и добавляем новое состояние в множество всех состояний машины
                fsmStates.add(nextState);

                // определяем переход из текущего состояния в следующее
                currentState.put(currentChar, nextState);

                // если текущий символ пробельный,
                if (isSpace)
                    // то заставляе машину  его пропустить без изменения состояния
                    nextState.put(' ', nextState);
            }
            // положить текущее состояние равным следующему ... переход на след. итерацию
            currentState = nextState;
        }

        // с каким термином связано состояние
        currentState.addTerm(term);
    }

    public void setPrefRepresentation(String prefRepresentation) {
        this.prefRepresentation = prefRepresentation;
    }

    public String getPrefRepresentation() {
        return prefRepresentation;
    }

    public String getLanguage() {
        return language.getLanguage();
    }

    public void setLanguage(String language) {
        this.language = new Locale(language);
    }

    public String getAltRepresentation() {
        return altRepresentation;
    }

    public void setAltRepresentation(String altRepresentation) {
        this.altRepresentation = altRepresentation;
    }

    public Ontology getOntology() {
        return ontology;
    }

    public void setOntology(Ontology ontology) {
        this.ontology = ontology;
    }
}